using System;
using LegoBotPrimaAbstractions;
using LegoBotPrimaAbstractions.Extensions;
using NUnit.Framework;

namespace LegoBotPrimaTests
{
    public class Extension_Fixture : BaseFixture
    {

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Clockwize()
        {
            var now = DateTime.Now;
            var data = new SensorData{TimeStamp = now.AddMilliseconds(80)};
            data.DefineAngleByClockwiseNeighbours(new SensorData { Angle = 10, TimeStamp = now }, new SensorData { Angle = 60, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(50));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Clockwize_For_More_Than_180_Degrees()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(90) };
            data.DefineAngleByClockwiseNeighbours(new SensorData { Angle = 10, TimeStamp = now }, new SensorData { Angle = 210, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(190));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Clockwize_Across_0_Angle()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(80) };
            data.DefineAngleByClockwiseNeighbours(new SensorData { Angle = 350, TimeStamp = now }, new SensorData { Angle = 40, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(30));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Clockwize_Across_0_Angle_For_More_Than_180_Degrees()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(90) };
            data.DefineAngleByClockwiseNeighbours(new SensorData { Angle = 350, TimeStamp = now }, new SensorData { Angle = 190, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(170));
        }





        

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Counterclockwise()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(80) };
            data.DefineAngleByCounterclockwiseNeighbours(new SensorData { Angle = 60, TimeStamp = now }, new SensorData { Angle = 10, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(20));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Counterclockwise_For_More_Than_180_Degrees()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(90) };
            data.DefineAngleByCounterclockwiseNeighbours(new SensorData { Angle = 210, TimeStamp = now }, new SensorData { Angle = 10, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(30));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Counterclockwise_Across_0_Angle()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(80) };
            data.DefineAngleByCounterclockwiseNeighbours(new SensorData { Angle = 40, TimeStamp = now }, new SensorData { Angle = 350, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(0));
        }

        [Test]
        public void SensorData_Angle_Can_Be_Defined_By_Neighbours_Counterclockwise_Across_0_Angle_For_More_Than_180_Degrees()
        {
            var now = DateTime.Now;
            var data = new SensorData { TimeStamp = now.AddMilliseconds(90) };
            data.DefineAngleByCounterclockwiseNeighbours(new SensorData { Angle = 110, TimeStamp = now }, new SensorData { Angle = 270, TimeStamp = now.AddMilliseconds(100) });
            Assert.That(data.Angle, Is.EqualTo(290));
        }



        




        [Test]
        public void IEnumerable_Of_SensorData_CalculateAngleChangeSpeed_Works_As_Expected()
        {
            var now = DateTime.Now;
            var data = new[]
                           {
                               new SensorData { Angle = 10, TimeStamp = now }, 
                               new SensorData { Angle = 20, TimeStamp = now.AddSeconds(1) }, 
                               new SensorData { Angle = 30, TimeStamp = now.AddSeconds(2) },
                               new SensorData { Angle = 60, TimeStamp = now.AddSeconds(5) },
                           };

            var speed = data.CalculateAngleChangeSpeed();

            Assert.That(speed, Is.EqualTo(10));
        }
        [Test]
        public void IEnumerable_Of_SensorData_CalculateDistanceChangeSpeed_Works_As_Expected()
        {
            var now = DateTime.Now;
            var data = new[]
                           {
                               new SensorData { Distance = 10, TimeStamp = now }, 
                               new SensorData { Distance = 20, TimeStamp = now.AddSeconds(1) }, 
                               new SensorData { Distance = 30, TimeStamp = now.AddSeconds(2) },
                               new SensorData { Distance = 60, TimeStamp = now.AddSeconds(5) },
                           };

            var speed = data.CalculateDistanceChangeSpeed();

            Assert.That(speed, Is.EqualTo(10));
        }


        [Test]
        public void SensorData_CalculateAngleChangeSpeed_Works_As_Expected()
        {
            var now = DateTime.Now;
            var current = new SensorData {  Angle = 10, TimeStamp = now};
            var previous = new SensorData { Angle = 20, TimeStamp = now.AddSeconds(-1)};

            var speed = current.CalculateAngleChangeSpeed(previous);

            Assert.That(speed, Is.EqualTo(10));
        }
        [Test]
        public void SensorData_CalculateDistanceChangeSpeed_Works_As_Expected()
        {
            var now = DateTime.Now;
            var current = new SensorData { Distance = 10, TimeStamp = now };
            var previous = new SensorData { Distance = 20, TimeStamp = now.AddSeconds(-1) };

            var speed = current.CalculateDistanceChangeSpeed(previous);

            Assert.That(speed, Is.EqualTo(10));
        }

        [Test]
        public void IEnumerable_Of_SensorData_CalculateAngleChangeSpeed_Throws_ArgumentException_If_Empty()
        {
            var data = new SensorData[] { };
            Assert.Throws(typeof(ArgumentException), () => data.CalculateAngleChangeSpeed());
        }
        [Test]
        public void IEnumerable_Of_SensorData_CalculateAngleChangeSpeed_Throws_ArgumentException_If_Single()
        {
            var data = new [] { new SensorData()  };
            Assert.Throws(typeof(ArgumentException), () => data.CalculateAngleChangeSpeed());
        }
        [Test]
        public void IEnumerable_Of_SensorData_CalculateAngleChangeSpeed_Does_Not_Throws_Argument_Exception_If_Multiple()
        {
            var data = new[] { new SensorData(), new SensorData() };
            Assert.DoesNotThrow(() => data.CalculateAngleChangeSpeed());
        }

        [Test]
        public void IEnumerable_Of_SensorData_CalculateDistanceChangeSpeed_Throws_ArgumentException_If_Empty()
        {
            var data = new SensorData[] { };
            Assert.Throws(typeof(ArgumentException), () => data.CalculateDistanceChangeSpeed());
        }
        [Test]
        public void IEnumerable_Of_SensorData_CalculateDistanceChangeSpeed_Throws_ArgumentException_If_Single()
        {
            var data = new[] { new SensorData() };
            Assert.Throws(typeof(ArgumentException), () => data.CalculateDistanceChangeSpeed());
        }
        [Test]
        public void IEnumerable_Of_SensorData_CalculateDistanceChangeSpeed_Does_Not_Throws_Argument_Exception_If_Multiple()
        {
            var data = new[] { new SensorData(), new SensorData() };
            Assert.DoesNotThrow(() => data.CalculateDistanceChangeSpeed());
        }

        
        [Test]
        public void DateTime_AsInitCall_Works_As_Expected()
        {
            var dt = new DateTime(2010, 7, 18, 4, 37, 14, 235);
            Assert.That(dt.AsInitCall(), Is.EqualTo("new DateTime(2010, 7, 18, 4, 37, 14, 235)"));
        }

        
    }
}